package com.winning.pmph.ctrl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.winning.pmph.entity.*;
import com.winning.pmph.mapper.BookArticleMapper;
import com.winning.pmph.mapper.BookCatalogItemMapper;
import com.winning.pmph.mapper.BookLogMapper;
import com.winning.pmph.service.BookService;
import com.winning.pmph.service.KnowledgeUnitService;
import com.winning.pmph.service.TagService;
import com.winning.pmph.utils.*;
import com.winning.pmph.vo.IncreaseBookVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Api(value = "知识资源管理/图书管理")
@RestController
@RequestMapping("/pmph/action/book")
public class BookCtrl {
    @Resource
    private BookService bookService;
    @Resource
    private BookArticleMapper bookArticleMapper;
    @Resource
    private BookCatalogItemMapper bookCatalogItemMapper;
    @Resource
    private BookLogMapper bookLogMapper;
    @Resource
    private KnowledgeUnitService knowledgeUnitService;
    @Resource
    private TagService tagService;

    @ApiOperation(value = "selectBookArticleByKnowledgeUnitId", notes = "根据素材ID, 查询图书文章")
    @GetMapping("selectBookArticleByKnowledgeUnitId")
    public BookArticle selectBookArticleByKnowledgeUnitId(String knowledgeUnitId) {
        KnowledgeUnit knowledgeUnit = knowledgeUnitService.getById(knowledgeUnitId);
        BookCatalogItem bookCatalogItem = bookCatalogItemMapper.selectById(knowledgeUnit.getBookCatalogItemId());
        BookArticle bookArticle = bookArticleMapper.selectById(bookCatalogItem.getBookArticleId());
        Element unitContent = Jsoup.parse(bookArticle.getUnitContent()).body();
        Optional<Element> crtBookCatalogItemTag = unitContent.children().stream().filter(item -> item.tagName().startsWith("h"))
                .filter(item -> StringUtils.equals(item.text(), bookArticle.getTitle()))
                .findFirst();
        if (crtBookCatalogItemTag.isPresent()) {
            bookArticle.setCrtBookCatalogItemTagId(crtBookCatalogItemTag.get().id());
        }
        return bookArticle;
    }

    @ApiOperation(value = "selectPreSibling", notes = "根据图书ID, 文章ID, 查询下一篇文章")
    @GetMapping("selectPreSibling")
    public BookArticle selectPreSibling(String bookId, String bookArticleId) {
        BookArticle bookArticle = bookService.getPreSibling(bookId, bookArticleId);
        if (Objects.isNull(bookArticle)) {
            throw new RuntimeException("已经是第一篇文章");
        }
        return bookArticle;
    }

    @ApiOperation(value = "selectNextSibling", notes = "根据图书ID, 文章ID, 查询下一篇文章")
    @GetMapping("selectNextSibling")
    public BookArticle selectNextSibling(String bookId, String bookArticleId) {
        BookArticle bookArticle = bookService.getNextSibling(bookId, bookArticleId);
        if (Objects.isNull(bookArticle)) {
            throw new RuntimeException("已经是最后一篇文章");
        }
        return bookArticle;
    }

    @ApiOperation(value = "selectBookArticle", notes = "图书点击左侧树节点展示内容接口")
    @GetMapping("selectBookArticle")
    public BookArticle selectBookArticle(String bookArticleId) {
        BookArticle bookArticle = bookArticleMapper.selectById(bookArticleId);
        return bookArticle;
    }

    /**
     * 图书标注完成, 修改标注状态;
     *
     * @param book
     */
    @ApiOperation(value = "insertMaterial", notes = "图书标注完成, 修改标注状态接口")
    @PostMapping("insertMaterial")
    public void insertMaterial(@RequestBody Book book) {
        bookService.insertMaterial(book);
    }

    /**
     * 查询数据
     */
    @ApiOperation(value = "selectDraftList", notes = "图书草稿库查询列表接口")
    @GetMapping("selectDraftList")
    public Page<Book> selectDraftList(Book book) {
        Page<Book> bookPage = bookService.queryDraftPage(book);
        return bookPage;
    }

    @ApiOperation(value = "release", notes = "草稿库发布图书接口")
    @GetMapping("release")
    public void release(String id) {
        bookService.publishBook(id);
    }

    @ApiOperation(value = "selectBookLog", notes = "图书查看日志接口")
    @GetMapping("selectBookLog")
    public List<BookLog> selectBookLog(String id) {
        return bookLogMapper.selectList(Wrappers.lambdaQuery(BookLog.class)
                .eq(BookLog::getBookId, id));
    }

    @ApiOperation(value = "deleteBookById", notes = "删除图书接口")
    @GetMapping("deleteBookById")
    public void deleteBookById(String id) {
        bookService.deleteBookById(id, "book");
    }

    @ApiOperation(value = "confirm", notes = "图书元数据保存接口")
    @PostMapping("confirm")
    public void confirm(String data, String id) {
        JSONObject metadataJson = JSONObject.parseObject(data);
        bookService.updateMetadata(metadataJson, id);
    }

    @ApiOperation(value = "selectBookTree", notes = "图书详情获左侧树结构接口")
    @GetMapping("selectBookTree")
    public List<BookCatalogItem> selectBookTree(String bookId) {
        List<BookCatalogItem> catalogItemList = bookCatalogItemMapper.selectList(Wrappers.lambdaQuery(BookCatalogItem.class)
                .eq(BookCatalogItem::getBookId, bookId));
        Map<String, BookCatalogItem> id2item = catalogItemList.stream().collect(Collectors.toMap(BookCatalogItem::getId, item -> item));
        for (BookCatalogItem bookCatalogItem : catalogItemList) {
            if (StringUtils.isBlank(bookCatalogItem.getParentId())) {
                continue;
            } else {
                BookCatalogItem parentNode = id2item.get(bookCatalogItem.getParentId());
                if (Objects.isNull(parentNode.getChildren())) {
                    parentNode.setChildren(Lists.newArrayList());
                }
                parentNode.getChildren().add(bookCatalogItem);
            }
        }
        // 查询一级
        List<BookCatalogItem> oneLevelTag = catalogItemList.stream().filter(t -> StringUtils.isBlank(t.getParentId())).collect(Collectors.toList());
        return oneLevelTag;
    }

    @ApiOperation(value = "downLoad", notes = "图书下载补录模板接口")
    @GetMapping("downLoad")
    public void downLoad(HttpServletResponse response) {
        // 创建一个Excel文件
        XSSFWorkbook wb = new XSSFWorkbook();
        // 创建第一个工作表
        XSSFSheet sheet = wb.createSheet("图书元数据批量补录模板.xlsx");
        sheet.setColumnWidth(0, 9100);
        sheet.setColumnWidth(1, 9100);
        sheet.setColumnWidth(2, 9100);
        // 添加表头行
        XSSFRow xssfRow = sheet.createRow(0);

        // 添加表头内容
        XSSFCell headCell = xssfRow.createCell(0);
        headCell.setCellValue("isbn");
        headCell = xssfRow.createCell(1);
        headCell.setCellValue("markup");
        headCell = xssfRow.createCell(2);
        headCell.setCellValue("value");

        XSSFRow row1 = sheet.createRow(1);
        XSSFCell cell10 = row1.createCell(0);
        cell10.setCellValue("978-7-117-19759-5");
        XSSFCell cell12 = row1.createCell(1);
        cell12.setCellValue("Titles/Alternative_Title");
        XSSFCell cell13 = row1.createCell(2);
        cell13.setCellValue("实用普通外科手术学");

        XSSFRow row2 = sheet.createRow(2);
        XSSFCell cell20 = row2.createCell(0);
        cell20.setCellValue("978-7-117-19759-5");
        XSSFCell cell22 = row2.createCell(1);
        cell22.setCellValue("Titles/Other_Title");
        XSSFCell cell23 = row2.createCell(2);
        cell23.setCellValue("实用普通外科手术学");

        XSSFRow row3 = sheet.createRow(3);
        XSSFCell cell30 = row3.createCell(0);
        cell30.setCellValue("978-7-117-19759-5");
        XSSFCell cell32 = row3.createCell(1);
        cell32.setCellValue("Creators/Creator");
        XSSFCell cell33 = row3.createCell(2);
        cell33.setCellValue("杨春明/主编/null");

        try {
            response.setContentType("application/xlsx;charset=UTF-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("图书元数据批量补录模板.xlsx", "UTF-8"));
            wb.write(response.getOutputStream());
            response.getOutputStream().close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    @ApiOperation(value = "selectOfficialList", notes = "图书正式库查询列表接口")
    @GetMapping("selectOfficialList")
    public Page<Book> selectOfficialList(int currentPage,
                                         int pageNum,
                                         String name,
                                         String category,
                                         String updateTime,
                                         String ISBN,
                                         String syncStatus,
                                         String bindingPlatform,
                                         String version) {
        Page<Book> bookPage = bookService.queryOfficialList(new Page<>(currentPage, pageNum), name, category, updateTime, ISBN, syncStatus, bindingPlatform, version);
        return bookPage;
    }

    @ApiOperation(value = "cancelRelease", notes = "图书正式库取消发布接口")
    @GetMapping("cancelRelease")
    public void cancelRelease(String id) {
        bookService.revokePublish(id);
    }

    @ApiOperation(value = "editConfirm", notes = "图书点击详情保存接口")
    @PostMapping("editConfirm")
    public void editConfirm(String bookArticleId, String unitContent) {
        BookArticle bookArticle = bookArticleMapper.selectById(bookArticleId);
        bookArticle.setUnitContent(unitContent);
        bookArticleMapper.updateById(bookArticle);
    }

    @ApiOperation(value = "fillUp", notes = "图书批量补录接口")
    @PostMapping("fillUp")
    public String fillUp(HttpServletRequest request) {
        String fileName = "";
        try {
            Map<String, JSONObject> isbn2MetadataMap = new HashMap<>();
            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            List<FileItem> fileItems = upload.parseRequest(request);
            Iterator<FileItem> it = fileItems.iterator();
            while (it.hasNext()) {
                FileItem next = it.next();
                XSSFWorkbook xssfWorkbook = new XSSFWorkbook(next.getInputStream());
                fileName = next.getName();
                for (int j = 0; j < xssfWorkbook.getNumberOfSheets(); j++) {
                    XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(j);
                    String sheetName = xssfSheet.getSheetName();
                    for (int k = 1; k < xssfSheet.getPhysicalNumberOfRows(); k++) {
                        XSSFRow xssfRow = xssfSheet.getRow(k);
                        String isbn = xssfRow.getCell(0).getStringCellValue();
                        String markupPath = xssfRow.getCell(1).getStringCellValue();
                        String value = xssfRow.getCell(2).getStringCellValue();
                        // 校验参数;
                        BookExcelUtil.checkParameter(fileName, sheetName, k, isbn, markupPath, value);
//                    updateBookMetadata(isbn, markupPath, value);
                        if (Objects.isNull(isbn2MetadataMap.get(isbn))) {
                            List<Book> book = bookService.lambdaQuery().eq(Book::getIsbn, isbn).list();
                            if (book.size() == 0) {
                                throw new RuntimeException("图书isbn:" + isbn + "不存在");
                            }
                            isbn2MetadataMap.put(isbn, book.get(0).getMetadata());
                        }
                        BookExcelUtil.setMetadataValue(isbn2MetadataMap.get(isbn), markupPath, value);
                    }
                }
            }
            bookService.batchUpdateMetadata(isbn2MetadataMap);
            return fileName + "补录成功";
        } catch (Exception e) {
            throw new RuntimeException(fileName + "补录失败, 失败原因:" + e.getMessage());
        }
    }

    @ApiOperation(value = "releaseAllBook", notes = "图书一键发布接口")
    @PostMapping("releaseAllBook")
    public void releaseAllBook(String selectAll) {
        JSONArray objects = JSONArray.parseArray(selectAll);
        for (int i = 0; i < objects.size(); i++) {
            JSONObject dataJson = objects.getJSONObject(i);
            String id = dataJson.getString("id");
            bookService.publishBook(id);
        }
    }

    /**
     * 推送图书
     */
    @ApiOperation(value = "syncBook", notes = "推送图书接口")
    @GetMapping("syncBook")
    public void syncBook(String ids,
                         String bindingPlatform,
                         String name,
                         String category,
                         String updateTime,
                         String isbn,
                         String syncStatus, String version) {
        // 一键同步
        if (StringUtils.isBlank(ids)) {
            Page<Book> bookPage = bookService.queryOfficialList(new Page<>(), name, category, updateTime, isbn, syncStatus, bindingPlatform, version);
            ids = bookPage.getRecords().stream().map(Book::getId).collect(Collectors.joining(","));
        }
        String[] idArray = ids.split(",");
        String userName = PMPHAppUtil.getCurrentUserEnName();
        ExecutorServiceFactory.getInstance().submit(() -> {
            Arrays.asList(idArray).forEach(id -> {
                bookService.syncBook(id, bindingPlatform, userName);
            });
        });
    }

    @ApiOperation(value = "selectBookList", notes = "获取图书ID, name")
    @GetMapping("selectBookList")
    public List<Book> selectBookList() {
        return bookService.lambdaQuery().select(Book::getId, Book::getName, Book::getCategory).list();
    }

    @ApiOperation(value = "selectBookCategoryCascaderOptions", notes = "图书分类信息, 并把图书数量挂载到分类下")
    @GetMapping("selectBookCategoryCascaderOptions")
    public List<Tag> selectBookCategoryCascaderOptions() {
        return tagService.selectBookCategoryCascaderOptions();
    }

    @ApiOperation(value = "importBook", notes = "导入图书的XML文件")
    @PostMapping("importBook")
    public void importBook(MultipartFile file, String id, String forceFlag, HttpServletRequest request) {
        String header = request.getHeader("user-agent");
        String userName = PMPHAppUtil.getCurrentUserEnName();
        try {
            Book book = new Book();
            book.setName(StringUtils.removeEnd(file.getName(), ".zip"));
            book.setId(IdWorker.getIdStr());
            if (StringUtils.isNotBlank(id)) {
                book = bookService.getById(id);
            }
            book.setUpdatedBy(userName);
            book.setStatus(Book.BOOK_IMPORT_STATUS_IMPORTING);
            bookService.saveOrUpdate(book);
            Book finalBook = book;
            // 当导入失败时,只修改状态
            Book failureBook = JSON.parseObject(JSON.toJSONString(finalBook), Book.class);
            ExecutorServiceFactory.getInstance().submit(() -> {
                try {
                    String path = ApplicationContextUtil.BASE_DOWN_FORDER + "image/book/temp/";
                    String name = UploadFileUtil.uploadFile(file, path, false);
                    finalBook.setZipPath(path + name);
                    //开始解压图书
                    bookService.importXml(finalBook, forceFlag, header);
                    bookService.saveOrUpdate(finalBook);
                } catch (Exception e) {
                    failureBook.setStatus(Book.BOOK_IMPORT_STATUS_FAILED);
                    failureBook.setFailureReason(e.getMessage());
                    bookService.saveOrUpdate(failureBook);
                    throw new RuntimeException("图书文件上传失败" + e);
                } finally {
                    // 删除解压文件; 删除上传的zip包
                    try {
                        FileUtils.deleteDirectory(new File(StringUtils.removeEnd(finalBook.getZipPath(), ".zip")));
                        FileUtils.deleteQuietly(new File(finalBook.getZipPath()));
                    } catch (IOException e) {
                        throw new RuntimeException(e.getMessage());
                    }
                }
            });
        } catch (Exception e) {
            throw new RuntimeException("导入任务提交失败, 失败原因: " + e.getMessage());
        }
    }

    @ApiOperation(value = "insertIncreaseBook", notes = "新增增值服务图书")
    @PostMapping("insertIncreaseBook")
    public Book insertIncreaseBook(@RequestBody IncreaseBookVo increaseBookVo) {
        return bookService.insertIncreaseBook(increaseBookVo);
    }

    @ApiOperation(value = "updateIncreaseMetadata", notes = "修改增值服务图书元数据")
    @PostMapping("updateIncreaseMetadata")
    public void updateIncreaseMetadata(@RequestBody IncreaseBookVo increaseBookVo) {
        bookService.updateIncreaseMetadata(increaseBookVo);
    }

    @ApiOperation(value = "selectCategoryAndSummaryAndByIsbn", notes = "根据ISBN号查询图书分类,简介,价格等信息")
    @GetMapping("selectCategoryAndSummaryAndByIsbn")
    public Book selectCategoryAndSummaryAndByIsbn(String isbn, Integer bookType) {
        return bookService.selectCategoryAndSummaryAndByIsbn(isbn, bookType);
    }

    @ApiOperation(value = "selectBookById", notes = "根据图书ID查询图书信息")
    @GetMapping("selectBookById")
    public Book selectBookById(String id) {
        return bookService.getById(id);
    }
}